#include "libloader.h"


LibLoader* LibLoader::instance = 0;

LibLoader::LibLoader(QObject *parent) :
    QObject(parent)
{
    this->libRoot = QCoreApplication::applicationDirPath() + "/lib/";
}

LibLoader* LibLoader::getInstance()
{
    if (instance == NULL)
    {
        instance = new LibLoader();
    }

    return instance;
}

void LibLoader::loadLib(const QString &libName)
{
    QFile fileDevice;
    fileDevice.setFileName(this->libRoot + libName + ".xml");
    if (!fileDevice.open(QFile::ReadOnly)) return;

    do
    {
        if (fileDevice.size() == 0) break;

        QDomDocument doc;
        doc.setContent(&fileDevice);

        QDomElement *eClasses = 0;
        QDomElement eLib;

        eLib = doc.documentElement(); //must be <lib>

        if (eLib.tagName() != SCN_LIB) break;

        QDomNode node = eLib.firstChild(); //must be <lib><node></lib>
        while (!node.isNull())
        {
            QDomElement e = node.toElement();
            QString tag = e.tagName();
            if (tag == SCN_CLASSES) eClasses = &e;
            node = node.nextSibling();
        }

        if (!eClasses) break;

        loadClasses(eClasses, libName, eLib.attribute(ATTR_LIB_PATH, this->libRoot + libName));
    } while (0);

    fileDevice.close();
}

void LibLoader::loadClasses(QDomElement* root, const QString& libName, const QString& libPath)
{
    if (root)
    {
        QDomNodeList nlst = root->elementsByTagName(TAG_CLASS);
        for (unsigned int i = 0; i < nlst.length(); i++)
        {
            QDomElement e = nlst.at(i).toElement();
            MetaClass *mClass = new MetaClass(e.attribute(ATTR_CL_NAME), libName, libPath);
            this->libHash.insert(mClass->getClassName(), mClass);
        }
    }
}

MetaClass const * LibLoader::getClass(const QString& className, const QString& libName) const
{
    QMultiHash<QString, MetaClass*>::const_iterator i = this->libHash.find(className);

    if (libName.length() > 0)
    {
        while (i != this->libHash.end() && i.key() == className) {
            MetaClass* cl = i.value();
            if (cl->getLibName().compare(libName) == 0)
            {
                return cl;
            }
            i++;
        }
    } else {
        if (this->libHash.values(className).size() > 1)
        {
            emit warning("Class loading... There are few libraries containing "
                         + className + ". Trying to load the first occurance of the class.");
        }
        return this->libHash.value(className);
    }

    return 0;
}

QObject * LibLoader::getClassInstance(const QString &className, const QString &libName) const
{
    const MetaClass* clas = getClass(className, libName);

    QObject* obj = 0;
    if (clas)
    {
        obj = clas->instantiate();
    }

    return obj;
}

LibLoader::~LibLoader()
{
    QMultiHash<QString, MetaClass*>::const_iterator i = this->libHash.begin();
    while (i != this->libHash.end()) {
        MetaClass* cl = i.value();
        delete cl;
        i++;
    }

    delete instance;
}
